package com.starview.star.operators.relation.runtime;

import java.util.ArrayList;
import java.util.List;

import com.starview.platform.data.EvaluationException;
import com.starview.platform.data.IFunction;
import com.starview.platform.data.IValue;
import com.starview.platform.data.type.IType;
import com.starview.platform.data.type.Refresher;
import com.starview.platform.data.type.StandardTypes;
import com.starview.platform.data.type.TypeUtils;
import com.starview.platform.data.type.TypeVar;
import com.starview.platform.data.value.Relation;
import com.starview.platform.data.value.Factory;
import com.starview.star.operators.CafeEnter;

public class RelationSetOps
{
  public static class RelationUnion implements IFunction
  {
    public static final String name = "__relation_union";

    @CafeEnter
    public static Relation enter(Relation left, Relation right, IFunction equals) throws EvaluationException
    {
      List<IValue> tmp = new ArrayList<IValue>(left.size());
      for (IValue el : left)
        tmp.add(el);

      outer: for (IValue el : right) {
        for (IValue lftEl : tmp)
          if (Factory.boolValue(equals.enter(el, lftEl)))
            continue outer;
        tmp.add(el);
      }

      return Relation.create(tmp);
    }

    @Override
    public IValue enter(IValue... args) throws EvaluationException
    {
      return enter((Relation) args[0], (Relation) args[1], (IFunction) args[1]);
    }

    @Override
    public IType getType()
    {
      return type();
    }

    public static IType type()
    {
      IType v = new TypeVar();
      IType eqType = TypeUtils.functionType(v, v, StandardTypes.booleanType);
      IType colType = TypeUtils.relationType(v);
      return Refresher.generalize(TypeUtils.functionType(colType, colType, eqType, colType));
    }
  }

  public static class RelationIntersect implements IFunction
  {
    public static final String name = "__relation_intersect";

    @CafeEnter
    public static Relation enter(Relation left, Relation right, IFunction equals) throws EvaluationException
    {
      List<IValue> tmp = new ArrayList<IValue>(Math.min(left.size(), right.size()));

      outer: for (IValue lEl : left) {
        for (IValue rEl : right) {
          if (Factory.boolValue(equals.enter(lEl, rEl))) {
            tmp.add(lEl);
            continue outer;
          }
        }
      }

      return Relation.create(tmp);
    }

    @Override
    public IValue enter(IValue... args) throws EvaluationException
    {
      return enter((Relation) args[0], (Relation) args[1], (IFunction) args[1]);
    }

    @Override
    public IType getType()
    {
      return type();
    }

    public static IType type()
    {
      IType v = new TypeVar();
      IType eqType = TypeUtils.functionType(v, v, StandardTypes.booleanType);
      IType colType = TypeUtils.relationType(v);
      return Refresher.generalize(TypeUtils.functionType(colType, colType, eqType, colType));
    }
  }

  public static class RelationComplement implements IFunction
  {
    public static final String name = "__relation_complement";

    @CafeEnter
    public static Relation enter(Relation left, Relation right, IFunction equals) throws EvaluationException
    {
      List<IValue> tmp = new ArrayList<IValue>(left.size());

      outer: for (IValue lEl : left) {
        for (IValue rEl : right) {
          if (Factory.boolValue(equals.enter(lEl, rEl)))
            continue outer;
        }
        tmp.add(lEl);
      }

      return Relation.create(tmp);
    }

    @Override
    public IValue enter(IValue... args) throws EvaluationException
    {
      return enter((Relation) args[0], (Relation) args[1], (IFunction) args[1]);
    }

    @Override
    public IType getType()
    {
      return type();
    }

    public static IType type()
    {
      IType v = new TypeVar();
      IType eqType = TypeUtils.functionType(v, v, StandardTypes.booleanType);
      IType colType = TypeUtils.relationType(v);
      return Refresher.generalize(TypeUtils.functionType(colType, colType, eqType, colType));
    }
  }
}
